package com.example.javamediaserver.service;

import com.example.javamediaserver.config.MediaServerConfig;
import com.example.javamediaserver.model.Recording;
import com.example.javamediaserver.repository.RecordingRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Service
@RequiredArgsConstructor
@Slf4j
public class RecordingService {

    private final RecordingRepository repository;
    private final MediaServerConfig config;
    private final StreamSessionService streamSessionService;
    
    @PostConstruct
    public void init() {
        // 确保录制目录存在
        try {
            Path recordingsPath = config.getRecordings().getAbsolutePath();
            Files.createDirectories(recordingsPath);
            log.info("录制目录已创建: {}", recordingsPath);
            
            // 初始化时加载现有录制文件
            updateRecordingsFromDisk();
        } catch (IOException e) {
            log.error("创建录制目录失败", e);
        }
    }
    
    // 开始录制流
    public Recording startRecording(String sessionId, String streamPath, String app, String streamKey) {
        if (!config.getRecordings().isEnabled()) {
            log.warn("录制功能已禁用");
            return null;
        }
        
        try {
            // 创建录制文件名
            String fileName = createRecordingFileName(app, streamKey);
            Path recordingPath = config.getRecordings().getAbsolutePath().resolve(fileName);
            
            // 创建录制记录
            Recording recording = new Recording();
            recording.setId(UUID.randomUUID().toString());
            recording.setFileName(fileName);
            recording.setFilePath(recordingPath.toString());
            recording.setStreamPath(streamPath);
            recording.setApp(app);
            recording.setStreamKey(streamKey);
            recording.setCreatedTime(LocalDateTime.now());
            recording.setFileSize(0);
            recording.setDurationInSeconds(0);
            
            // 保存录制记录
            repository.save(recording);
            
            // 更新会话状态
            streamSessionService.startRecording(sessionId, recordingPath.toString());
            
            log.info("开始录制: {} -> {}", streamPath, recordingPath);
            
            return recording;
        } catch (Exception e) {
            log.error("开始录制失败: {}", streamPath, e);
            return null;
        }
    }
    
    // 结束录制
    public void stopRecording(String sessionId, String recordingId) {
        try {
            // 更新会话状态
            streamSessionService.stopRecording(sessionId);
            
            // 更新录制文件信息
            repository.findById(recordingId).ifPresent(recording -> {
                File file = new File(recording.getFilePath());
                if (file.exists()) {
                    recording.setFileSize(file.length());
                    // 粗略估计时长: 假设平均码率为250KB/s
                    recording.setDurationInSeconds(file.length() / (250 * 1024));
                    repository.save(recording);
                }
                
                log.info("结束录制: {}, 大小: {}", recording.getStreamPath(), recording.getFileSize());
            });
        } catch (Exception e) {
            log.error("结束录制失败: {}", sessionId, e);
        }
    }
    
    // 从磁盘更新录制文件列表
    public void updateRecordingsFromDisk() {
        try {
            Path recordingsPath = config.getRecordings().getAbsolutePath();
            File[] files = recordingsPath.toFile().listFiles((dir, name) -> name.endsWith(".flv"));
            
            if (files != null) {
                for (File file : files) {
                    // 检查数据库中是否已存在
                    Optional<Recording> existingRecording = repository.findByFileName(file.getName());
                    if (existingRecording.isPresent()) {
                        // 更新文件大小和时长
                        Recording recording = existingRecording.get();
                        recording.setFileSize(file.length());
                        recording.setDurationInSeconds(file.length() / (250 * 1024));
                        repository.save(recording);
                    } else {
                        // 创建新记录
                        Recording recording = new Recording();
                        recording.setId(UUID.randomUUID().toString());
                        recording.setFileName(file.getName());
                        recording.setFilePath(file.getAbsolutePath());
                        recording.setCreatedTime(LocalDateTime.ofInstant(
                                java.nio.file.Files.getLastModifiedTime(file.toPath()).toInstant(),
                                java.time.ZoneId.systemDefault()));
                        recording.setFileSize(file.length());
                        recording.setDurationInSeconds(file.length() / (250 * 1024));
                        
                        // 尝试从文件名解析元数据
                        recording.parseFromFileName();
                        
                        repository.save(recording);
                        log.info("添加现有录制文件: {}", file.getName());
                    }
                }
            }
        } catch (Exception e) {
            log.error("更新录制文件列表失败", e);
        }
    }
    
    // 获取所有录制文件
    public List<Recording> getAllRecordings() {
        return repository.findAll();
    }
    
    // 按应用和流密钥获取录制文件
    public List<Recording> getRecordingsByAppAndStreamKey(String app, String streamKey) {
        return repository.findByAppAndStreamKey(app, streamKey);
    }
    
    // 删除录制文件
    public boolean deleteRecording(String recordingId) {
        try {
            Optional<Recording> recordingOpt = repository.findById(recordingId);
            if (recordingOpt.isPresent()) {
                Recording recording = recordingOpt.get();
                
                // 删除文件
                File file = new File(recording.getFilePath());
                if (file.exists()) {
                    FileUtils.forceDelete(file);
                }
                
                // 删除数据库记录
                repository.delete(recording);
                
                log.info("删除录制文件: {}", recording.getFileName());
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("删除录制文件失败: {}", recordingId, e);
            return false;
        }
    }
    
    // 创建录制文件名
    private String createRecordingFileName(String app, String streamKey) {
        LocalDateTime now = LocalDateTime.now();
        String timestamp = now.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
        return String.format("%s_%s_%s.flv", app, streamKey, timestamp);
    }
} 